package com.szj.coroutine.project.jvm.blog4

import kotlinx.coroutines.*
import kotlinx.coroutines.channels.*
import kotlinx.coroutines.flow.*
import kotlinx.coroutines.selects.select
import kotlin.concurrent.thread
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.math.exp
import kotlin.system.measureTimeMillis

/*
 * 作者: 史大拿
 * 时间: 2023/2/17
 */

// TODO =================== 回顾 ======================
//fun main() {
//    val waitTime = measureTimeMillis {
//        runBlocking<Unit> {
//
//            println("main start")            // 1   // 调度前
//            launch {
//                println("launch 1 start")    // 2   // 调度后执行前
//                delay(1000)                // 延迟1s (不会阻塞兄弟协程)
//                println("launch 1 end")      // 3
//            }
//
//            println("main mid")              // 4   // 调度前
//
//            launch {
//                println("launch 2 start")    // 5   // 调度后执行
//                delay(500)                 // 延迟0.5s (不会阻塞兄弟协程)
//                println("launch 2 end")      // 6
//            }
//            println("main end")              // 7   // 调度前
//        }
//    }
//
//    println("等待时间:${waitTime}")
//}


// TODO =================== 最简单的例子 send / receive ======================
//fun main() = runBlocking<Unit> {
//    // 用来协程间的通信
////    val channel = Channel<String>(capacity = 10)
//    val channel = Channel<String>(capacity = 1, onBufferOverflow = BufferOverflow.SUSPEND)
//    println("main start")
//
//    launch {    // A 协程
//        delay(1000)
//        channel.send("我是launch[A]的数据 1")
//        channel.send("我是launch[A]的数据 2")
//        channel.send("我是launch[A]的数据 3")
//    }
//
//    launch {    // B 协程
//        println("result ${channel.receive()}")
//    }
//    println("main end")
//}

// TODO =================== trySend / tryReceive ======================
//fun main() = runBlocking<Unit> {
//    // 用来协程间的通信
//    val channel = Channel<String>(capacity = 1, onBufferOverflow = BufferOverflow.DROP_OLDEST)
//    println("main start")
//
//
//    launch { // A协程
////        channel.close()
//        val trySend = channel.trySend("A协程发送数据 1")
//        if (trySend.isSuccess) {
//            println("channel 发送成功")
//        } else if (trySend.isClosed) {
//            println("channel 关闭了")
//        } else if (trySend.isFailure) {
//            println("channel 发送失败")
//        }
//    }.join() // A协程必须执行完，通道有数据了之后才能取
//
//        val tryReceive = channel.tryReceive()
//        if (tryReceive.isSuccess) {
//            println("tryReceive 接收到了数据:${tryReceive.getOrNull()}")
//        } else if (tryReceive.isClosed) {
//            println("tryReceive 关闭了")
//        } else if (tryReceive.isFailure) {
//            println("tryReceive 发送失败")
//        }
//
//    println("main end")
//}

//// TODO =================== onSend / onReceive ======================
//fun main() = runBlocking<Unit> {
//    // 用来协程间的通信
//    val channel = Channel<String>(capacity = 5, onBufferOverflow = BufferOverflow.SUSPEND)
//    println("main start")
//
//    launch {    // A 协程 发送数据
//        channel.send("send发送数据 ")
//        channel.trySend("trySend发送数据")
//    }
//
//    //  select 接收数据 默认会挂起，等待数据返回
//    select {
//        channel.onReceive {
//            println("onReceive:$it")
//        }
//        channel.onReceiveCatching {
//            println("onReceiveCatching:${it.getOrNull()}")
//        }
//    }
//    println("result ${channel.receive()}")
//
//    channel.invokeOnClose {
//        println("channel close ")
//    }
//
//    println("main end")
//}


////// TODO =================== 利用flow实现协程间的通信 ======================
fun main() = runBlocking<Unit> {
    // 默认数据只有在collect中，没有emit数据时候返回
    val flow = MutableStateFlow("默认数据")
    launch {
        flow.collect {
            println("result : $it")
        }
    }
    launch {
        flow.emit("我是flow发送的数据 1")
    }.join()
    launch {
        flow.emit("我是flow发送的数据 2")
    }.join()
    launch {
        flow.emit("我是flow发送的数据 3")
    }.join()
}


//
////// TODO =================== produce ======================
//suspend fun main() = runBlocking {
//    // 内部封装了协程
//    val receiveChannel = produce<String> {
//        launch {
//            delay(2000) /// 耗时2s去网络请求
//            send("send发送数据")
//            close()
//        }
//    }
//    println("执行了，receive会挂起等待返回")
//    println("receiveChannel result: ${receiveChannel.receive()}")
//}


//// TODO =================== actor ======================
//suspend fun main() = runBlocking<Unit> {
//
//    // 内部封装了协程
//    val receiveChannel = actor<String>(capacity = 10) {
//        // 等待消费数据
//        println("actor result:" + receive())
//    }
//    println("执行了，receive会挂起等待返回")
//
//    delay(1000)
//    receiveChannel.send("延迟1s后的数据")
//}

//
//// TODO =================== select ======================
//private suspend fun cacheData(scope: CoroutineScope) = scope.async {
//    delay(2000)
//    "{msg:'加载缓存数据用时1s'}"
//}
//
//private suspend fun networkData(scope: CoroutineScope) = scope.async {
//    delay(1000)
//    "{msg:'加载网络数据用时1s'}"
//}
//
//fun main() = runBlocking<Unit> {
//    val cacheData = cacheData(this)
//    val networkData = networkData(this)
//
//    val result = select {
//        // onAwait 监听async 返回
//        cacheData.onAwait {
//            println("cache:result:${it}")
//            it
//        }
//        networkData.onAwait {
//            println("network result:${it}")
//            it
//        }
//    }
//    println("最终使用数据为:$result \tthread:${Thread.currentThread().name}")
//}


// TODO =================== select2 ======================
//fun main() {
//    val useTime = measureTimeMillis {
//        runBlocking<Unit> {
//            // 自定义协程作用域，在这里不建议直接launch，直接launch会成为runBlocking的子协程，看不出效果
//            val coroutineScope = CoroutineScope(EmptyCoroutineContext)
//            val job1 = coroutineScope.launch { delay(1000) }
//            val job2 = coroutineScope.launch { delay(2000_000) }
//            val job3 = coroutineScope.launch { delay(4000_000) }
//
//            // select会返回执行完成的协程
//            val result = select {
//                job1.onJoin { // 监听job是否执行完成
//                    "job1执行完成"
//                }
//                job2.onJoin { "job2执行完成" }
//                job3.onJoin { "job3执行完成" }
//            }
//            println("最终使用数据为:$result \tthread:${Thread.currentThread().name}")
//        }
//    }
//
//    println("使用时间:$useTime")
//}
